#include "s_utc_2_normaltime.h"

#define S_UTC2NORMALTIME_EmbeddedSys					1 

#if S_UTC2NORMALTIME_EmbeddedSys
#else

#include <stdio.h>
#define S_UTC2NORMALTIME_Debug						printf

#endif

#ifndef NULL
#define NULL ((void *)0)
#endif



#define S_UTC2NORMALTIME_UTCBASEYEAR				1970
#define S_UTC2NORMALTIME_MONTHNUM_PER_YEAR			12
#define S_UTC2NORMALTIME_DAYNUM_PER_YEAR			365
#define S_UTC2NORMALTIME_SECNUM_PER_DAY				86400
#define S_UTC2NORMALTIME_SECNUM_PER_HOUR			3600
#define S_UTC2NORMALTIME_SECNUM_PER_MIN				60


static const unsigned char daynum_month[S_UTC2NORMALTIME_MONTHNUM_PER_YEAR] = 
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static unsigned char s_utc2normaltime_getweeknum(unsigned short year, unsigned char month, unsigned char day)
{
	char century_code, year_code, month_code, day_code;
    int week = 0;

    century_code = year_code = month_code = day_code = 0;

    if (month == 1 || month == 2) {
        century_code = (year - 1) / 100;
        year_code = (year - 1) % 100;
        month_code = month + 12;
        day_code = day;
    } else {
        century_code = year / 100;
        year_code = year % 100;
        month_code = month;
        day_code = day;
    }

    
    week = year_code + year_code / 4 + century_code / 4 - 2 * century_code + 26 * ( month_code + 1 ) / 10 + day_code - 1;
    week = week > 0 ? (week % 7) : ((week % 7) + 7);

    return week;
}

/*
	Return : 1 for leap year and 0 for not
*/
static signed char s_utc2normaltime_leapyearcheck(unsigned short year)
{
	if((year % 400) == 0)
	{
		return 1;
	}
	else if((year % 100) == 0)
	{
		return 0;
	}
	else if((year % 4) == 0)
	{
		return 1;
	}
	return 0;
}

static unsigned char s_utc2normaltime_getmonthdaynum(unsigned short year, \
														unsigned char month)
{
	if(month == 0 || month > 12)
	{
		return 0xFF;
	}
	if(month != 2)
	{
		return daynum_month[month - 1];
	}
	else
	{
		return daynum_month[1] + s_utc2normaltime_leapyearcheck(year);
	}
}

signed char S_UTC2NormalTime(unsigned int utc, \
					p_s_normaltime_str nmt)
{
	unsigned int ui_tdata, tday;
	unsigned short tyear;
	unsigned char tmonth;
	
	if(NULL == nmt)
	{
		return (-1);
	}
	
	//Get hour
	ui_tdata = utc % S_UTC2NORMALTIME_SECNUM_PER_DAY;
	nmt->hour = ui_tdata / S_UTC2NORMALTIME_SECNUM_PER_HOUR;
	
	//Get min
	ui_tdata %= S_UTC2NORMALTIME_SECNUM_PER_HOUR;
	nmt->min = ui_tdata / S_UTC2NORMALTIME_SECNUM_PER_MIN;
	
	//Get second
	nmt->sec = ui_tdata % S_UTC2NORMALTIME_SECNUM_PER_MIN;
	
	//Get year
	ui_tdata = utc / S_UTC2NORMALTIME_SECNUM_PER_DAY;
	for(tyear = S_UTC2NORMALTIME_UTCBASEYEAR; ui_tdata > 0; tyear++)
	{
		tday = S_UTC2NORMALTIME_DAYNUM_PER_YEAR + \
					s_utc2normaltime_leapyearcheck(tyear);
		if(ui_tdata >= tday)
		{
			ui_tdata -= tday;
		}
		else
		{
			break;
		}
	}
	nmt->year = tyear;
	
	//Get month
	for(tmonth = 1; tmonth < S_UTC2NORMALTIME_MONTHNUM_PER_YEAR; tmonth ++)
	{
		tday = s_utc2normaltime_getmonthdaynum(tyear, tmonth);
		if(ui_tdata >= tday)
		{
			ui_tdata -= tday;
		}
		else
		{
			break;
		}
	}
	nmt->month = tmonth;
	
	//Get day
	nmt->day = (unsigned char)(ui_tdata + 1);
	
	//Get week num
	nmt->weeknum = s_utc2normaltime_getweeknum(nmt->year, nmt->month, nmt->day);
		
	return 0;
}

signed char S_NormalTime2UTC(p_s_normaltime_str nmt, unsigned int *utc)
{
	unsigned short i;
	unsigned int no_of_days = 0U;
	
	if(NULL == nmt)
	{
		return (-1);
	}
	if(NULL == utc)
	{
		return (-2);
	}
	
	if(nmt->year < S_UTC2NORMALTIME_UTCBASEYEAR)
	{
		return (-3);
	}
	
	//Set year
	for (i = S_UTC2NORMALTIME_UTCBASEYEAR; i < nmt->year; i++) {
        no_of_days += (S_UTC2NORMALTIME_DAYNUM_PER_YEAR + \
							s_utc2normaltime_leapyearcheck(i));
    }
    
    //Set month
    for (i = 1; i < nmt->month; i++) {
        no_of_days += s_utc2normaltime_getmonthdaynum(nmt->year, (unsigned char) i);
    }
    
    //Set day
    no_of_days += (nmt->day - 1);
    
    *utc = (unsigned int) no_of_days * S_UTC2NORMALTIME_SECNUM_PER_DAY + \
				(unsigned int) (nmt->hour * S_UTC2NORMALTIME_SECNUM_PER_HOUR + \
					nmt->min * S_UTC2NORMALTIME_SECNUM_PER_MIN + \
						nmt->sec);
						
	return 0;
	
}

// void s_normaltime_int2hex(unsigned int utc, unsigned char *utchex)
// {
// 	unsigned char index_from_end = 3U;
// 	unsigned char mod_data_tens = 0U, mod_data_units = 0U;
	
// 	do
// 	{
// 		mod_data_units = utc % 16;
// 		utc /= 16;
// 		mod_data_tens = utc % 16;
// 		utc /= 16;
		
// 		utchex[index_from_end--] = mod_data_units | (mod_data_tens << 4);
		
// 	}while(utc);
		
// }

// void s_normaltime_hex2int(unsigned char *utchex, unsigned int *utc)
// {
// 	unsigned int mod_data_tens = 0U, mod_data_units = 0U;
	
// 	//signed char index_from_end = 3U;
	
// 	mod_data_tens = (utchex[3] >> 4);
// 	mod_data_units = utchex[3] & 0x0F;
// 	mod_data_tens *= (1 << 4);
// 	*utc = mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[2] >> 4);
// 	mod_data_units = utchex[2] & 0x0F;
// 	mod_data_units *= (1 << 8);
// 	mod_data_tens *= (1 << 12);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[1] >> 4);
// 	mod_data_units = utchex[1] & 0x0F;
// 	mod_data_units *= (1 << 16);
// 	mod_data_tens *= (1 << 20);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[0] >> 4);
// 	mod_data_units = utchex[0] & 0x0F;
// 	mod_data_units *= (1 << 24);
// 	mod_data_tens *= (1 << 28);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;

// }

// void s_normaltime_hex2int_fromlittlemode(unsigned char *utchex, unsigned int *utc)
// {
// 	unsigned int mod_data_tens = 0U, mod_data_units = 0U;
	
// 	mod_data_tens = (utchex[0] >> 4);
// 	mod_data_units = utchex[0] & 0x0F;
// 	mod_data_tens *= (1 << 4);
// 	*utc = mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[1] >> 4);
// 	mod_data_units = utchex[1] & 0x0F;
// 	mod_data_units *= (1 << 8);
// 	mod_data_tens *= (1 << 12);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[2] >> 4);
// 	mod_data_units = utchex[2] & 0x0F;
// 	mod_data_units *= (1 << 16);
// 	mod_data_tens *= (1 << 20);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;
	
// 	mod_data_tens = (utchex[3] >> 4);
// 	mod_data_units = utchex[3] & 0x0F;
// 	mod_data_units *= (1 << 24);
// 	mod_data_tens *= (1 << 28);
// 	*utc += mod_data_units;
// 	*utc += mod_data_tens;

// }

/*
signed char S_NormalTime2_Hex_UTC(p_s_normaltime_str nmt, unsigned char *utchex)
{
	unsigned int utc = 0U;
	if(S_NormalTime2UTC(nmt, &utc))
	{
		return (-1);
	}
	
	S_UTC2NORMALTIME_Debug("Get here and utc is %d\r\n", utc);
	
	s_normaltime_int2hex(utc, utchex);
	return 0;
}

signed char S_Hex_UTC2NormalTime(unsigned char *utchex, \
					p_s_normaltime_str nmt)
{
	unsigned int utc = 0U;
	s_normaltime_hex2int(utchex, &utc);
	S_UTC2NORMALTIME_Debug("The UTC from UTC Hex is %d\r\n", utc);
	return S_UTC2NormalTime(utc, nmt);
}
*/


#if !S_UTC2NORMALTIME_EmbeddedSys
static void s_utc2normaltime_str_show(p_s_normaltime_str nmt)
{
	if(NULL == nmt)
	{
		return;
	} 
	S_UTC2NORMALTIME_Debug("The time is %d-%02d-%02d %02d:%02d:%02d(%d)\r\n", nmt->year, nmt->month, nmt->day, nmt->hour, nmt->min, nmt->sec, nmt->weeknum);
} 

							
void S_UTC2NormalTime_Test(void)
{
	s_normaltime_str nmt;
	
	s_normaltime_str nmt_get_from_utchex;
	
	unsigned char utc_hex[4];
	
	unsigned int utc_kn = 1558420606;
	unsigned int utc_ukn = 0U;
	
	S_UTC2NormalTime(utc_kn, &nmt);
	S_NormalTime2UTC(&nmt, &utc_ukn);
	
 	s_utc2normaltime_str_show(&nmt);
 	S_UTC2NORMALTIME_Debug("The utc kn is %d and utc ukn is %d(%d)\r\n", utc_kn, utc_ukn, (utc_kn == utc_ukn)?0:1);
 	
 	S_NormalTime2_Hex_UTC(&nmt, utc_hex);
 	S_UTC2NORMALTIME_Debug("The UTC hex is 0x%02x%02x%02x%02x\r\n", utc_hex[0], utc_hex[1], utc_hex[2], utc_hex[3]);
 	S_Hex_UTC2NormalTime(utc_hex, &nmt_get_from_utchex);
 	s_utc2normaltime_str_show(&nmt_get_from_utchex);
 	//S_UTC2NORMALTIME_Debug("The UTC hex is 0x%02x%02x%02x%02x%02x%02x%02x%02x\r\n", utc_hex[0], utc_hex[1], utc_hex[2], utc_hex[3], utc_hex[4], utc_hex[5], utc_hex[6], utc_hex[7]);
}
#endif
